package iot.wlink.network.handler;

import cn.hutool.core.util.ObjectUtil;
import iot.wlink.network.devices.manager.AbstractDeviceManager;
import iot.wlink.network.payload.up.PointValue;
import iot.wlink.network.payload.up.ReportAckPayload;
import iot.wlink.network.payload.up.ReportPayload;
import iot.wlink.network.payload.up.UpPayload;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author : willian fu
 * @date : 2021/8/22
 * 数据处理服务，处理标准协议
 */
@Slf4j
@Component
public class DataStreamHandler {

    /**
     * 处理设备上报的标准协议数据
     *
     * @param payload 数据包
     */
    public void handler(UpPayload payload) {
        if (payload instanceof ReportPayload) {
            report((ReportPayload) payload);
        } else if (payload instanceof ReportAckPayload) {
            ack((ReportAckPayload) payload);
        } else {
            log.warn("来自[uid={} 协议{}]无法解析的数据包", payload.getUid(), payload.getProtocolsType());
        }
    }

    /**
     * 处理设备上报的数据
     *
     * @param payload 数据包
     */
    private void report(ReportPayload payload) {
        //获取设备管理器
        AbstractDeviceManager deviceManager = payload.getProtocolsType().getDeviceManager();
        if (ObjectUtil.isNull(deviceManager)) {
            log.warn("无法获取[uid={}]的设备管理器，不能处理", payload.getUid());
        } else {
            //将最新的状态更新到设备影子
            deviceManager.updateShadowActual(payload.getUid(), getLastPointVals(payload.getPayload()));
        }
    }

    /**
     * 处理设备的应答数据
     *
     * @param payload 数据包
     */
    private void ack(ReportAckPayload payload) {

    }

    /**
     * 提取最新的数据
     * @param pointValues 点位值
     * @return 最新点位值
     */
    private Map<String, PointValue> getLastPointVals(Map<String, List<PointValue>> pointValues) {
        return pointValues.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        e -> e.getValue().stream()
                                .max(Comparator.comparing(PointValue::getTime))
                                .get()));
    }

    private void toDatabase() {

    }

    private void toInflux() {

    }

}
